.. _глава_23_start:

Тернарный опрератор
===================

.. index::
    ?:
    тернарный оператор

Оператор ?: работает аналогично оператору if-else

.. code-block:: d

    if ( /* условие */)
    {
        /* выражение вычисляется в случае если условие истинно ...  */
    } else {
        /* выражение вычисляется в случае если услове ложно ...  */
    }


if оператор вычисляет либо блок для случая когнда условие истинно, либо блок когда условие ложно.
Однако как вы помните будучи оператором if не возвращает значение, а только управляет какой блок кода нужно
вычислить. С другой стороныоператор ?: - есть выражение и он способен вернуть значение. Рассмотрим аналошичный код реализованный
через этот оператор.

.. code-block:: d

    /* condition */ ? /* truth expression */ : /* falsity expression */

Поскольку в нем используются три выражения, оператор ?: называется тернарным  оператором.
Значение, получаемое этим оператором, является либо значением выражения truth expression,
либо значением выражения falsity expression. Поскольку это выражение, его
можно использовать везде, где можно использовать выражения.
В следующих примерах оператор ?: противопоставляется оператору if-else.
Тернарный оператор является более кратким для случаев, аналогичных этим примерам.

Инициализация
-------------


Чтобы инициализировать переменную содержащую число дней в году можно использовать следующее выражение

.. code-block:: d

    int days = isLeapYear ? 366 : 365;


Если использовать if оператор, один из способов будет слкдующий
* определить переменную без значения
* присвоить её необходимое значение

 .. code-block:: d

    int days;
    if (isLeapYear)
    {
        days = 366;
    }
    else
    {
        days = 365;
    }



An alternative also using an if is to initialize the variable with the non-leap
year value and then increment it if it is a leap year:

Альтернативный вариант определить переменную игициализировав её числом дней в невискосном году
и инкрементировать её для случая вискосного года

.. code-block:: d

    int days = 365;
    if (isLeapYear)
    {
        ++days;
    }

Печать
------

Печатать ту или иную часть сообщения в зависимости от условия

.. code-block:: d

    writeln("The glass is half ", isOptimistic ? "full." : "empty.");

Если использовать оператор if каждая часть мжет быть напечатано по отдельности

.. code-block:: d

    write("The glass is half ");
    if (isOptimistic)
    {
        writeln("full.");
    }
    else
    {
        writeln("empty.");
    }

Вычисления
----------

Увеличение счета победителя в игре в нарды на 2 очка или на 1
очко в зависимости от того, закончилась ли игра в нарды:

.. code-block:: d

    score += isGammon ? 2 : 1;

аналогичный код через оператор if

.. code-block:: d

    if (isGammon)
    {
        score += 2;
    }
    else
    {
        score += 1;
    }

Альтернативой, также использующей if, является сначала увеличение на единицу, а затем
повторное увеличение if gammon:

.. code-block:: d

    ++score;
    if (isGammon)
    {
        ++score;
    }

Как видно из приведенных выше примеров,
при использовании тернарного оператора в определенных ситуациях код становится более кратким и понятным.

Тип тернарного выражения
------------------------

Значением оператора ?: является либо значение выражения истинности, либо
значение выражения ложности. Типы этих двух выражений необязательно должны быть
одинаковыми, но они должны иметь общий тип.
Общий тип двух выражений определяется относительно сложным
алгоритмом, включающим преобразования типов (стр. 237) и наследование (стр. 328).
Кроме того, в зависимости от выражений, типом результата является либо
lvalue, либо rvalue (стр. 181). Мы рассмотрим эти концепции в последующих главах.
На данный момент примите common type как тип, который может представлять оба значения
не требуя явного приведения. Например, целочисленные типы int и long
имеют общий тип, потому что они оба могут быть представлены как long . С другой
стороны, int и string не имеют общего типа, потому что ни int, ни
string не могут быть автоматически преобразованы в другой тип.
Помните, что простым способом определения типа выражения является использование
type of и последующая печать его свойства .stringof:

.. code-block:: d

    int i;
    double d;
    auto result = someCondition ? i : d;
    writeln(typeof(result).stringof);

Поскольку double может представлять int, но не наоборот, общим
типом приведенного выше тернарного выражения является double :

.. code-block:: console

    double

Чтобы увидеть пример двух выражений, которые не имеют общего типа, давайте
рассмотрим создание сообщения, в котором сообщается количество отправляемых товаров. Давайте
выведем "Дюжина", когда значение равно 12: "Будет отправлено дюжина товаров".
В противном случае, пусть в сообщении будет указано точное количество: "Будет
отправлено 3 товара".
Можно подумать, что изменяющуюся часть сообщения можно выбрать с
помощью оператора ?::

.. code-block:: d

    writeln((count == 12) ? "A dozen" : count, " items will be shipped.") // ошибка компиляции ;

К сожалению, выражения не имеют общего типа, потому что тип "
Дюжина" является строковым, а тип count - int .
Решение состоит в том, чтобы сначала преобразовать count в string . Функция to!string из модуля
std.conv выдает строковое значение из указанного параметра:

.. code-block:: d

    import std.conv;
    // ...
    writeln((count == 12) ? "A dozen" : to!string(count)," items will be shipped.");

Теперь, поскольку оба выражения выбора оператора ?: имеют строковый тип,
код компилирует и печатает ожидаемое сообщение.

Упражнение
-----------

Попросите программу прочитать одно значение int как чистую сумму, где положительное значение
представляет прибыль, а отрицательное значение представляет убыток.
Программа должна напечатать сообщение, содержащее "получено" или "потеряно" в зависимости
от того, является ли сумма положительной или отрицательной. Например, "потеряно 100 долларов" или "получено 70 долларов
". Хотя это может быть более подходящим, не используйте оператор if в этом
упражнении.

Решение :ref:`Тернарный оператор<Тернарный оператор>`


